<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// $Id: CacheFile.class.php 2791 2012-02-29 10:08:57Z liu21st $


/**
 +------------------------------------------------------------------------------
 * 文件类型缓存类
 +------------------------------------------------------------------------------
 * @category   Think
 * @package  Think
 * @subpackage  Util
 * @author    liu21st <liu21st@gmail.com>
 * @version   $Id: CacheFile.class.php 2791 2012-02-29 10:08:57Z liu21st $
 +------------------------------------------------------------------------------
 */
class CacheFile extends Cache {
	
	/**
     +----------------------------------------------------------
	 * 缓存存储前缀
     +----------------------------------------------------------
	 * @var string
	 * @access protected
     +----------------------------------------------------------
	 */
	protected $prefix = '~@';
	
	/**
     +----------------------------------------------------------
	 * 架构函数
     +----------------------------------------------------------
	 * @access public
     +----------------------------------------------------------
	 */
	public function __construct($options = '') {
		if (! empty ( $options )) {
			$this->options = $options;
		}
		$this->options ['temp'] = ! empty ( $options ['temp'] ) ? $options ['temp'] : C ( 'DATA_CACHE_PATH' );
		$this->options ['expire'] = isset ( $options ['expire'] ) ? $options ['expire'] : C ( 'DATA_CACHE_TIME' );
		$this->options ['length'] = isset ( $options ['length'] ) ? $options ['length'] : 0;
		if (substr ( $this->options ['temp'], - 1 ) != '/')
			$this->options ['temp'] .= '/';
		$this->connected = is_dir ( $this->options ['temp'] ) && is_writeable ( $this->options ['temp'] );
		$this->init ();
	}
	
	/**
     +----------------------------------------------------------
	 * 初始化检查
     +----------------------------------------------------------
	 * @access private
     +----------------------------------------------------------
	 * @return boolen
     +----------------------------------------------------------
	 */
	private function init() {
		$stat = stat ( $this->options ['temp'] );
		$dir_perms = $stat ['mode'] & 0007777; // Get the permission bits.
		$file_perms = $dir_perms & 0000666; // Remove execute bits for files.
		

		// 创建项目缓存目录
		if (! is_dir ( $this->options ['temp'] )) {
			if (! mkdir ( $this->options ['temp'] ))
				return false;
			chmod ( $this->options ['temp'], $dir_perms );
		}
	}
	
	/**
     +----------------------------------------------------------
	 * 是否连接
     +----------------------------------------------------------
	 * @access public
     +----------------------------------------------------------
	 * @return boolen
     +----------------------------------------------------------
	 */
	private function isConnected() {
		return $this->connected;
	}
	
	/**
     +----------------------------------------------------------
	 * 取得变量的存储文件名
     +----------------------------------------------------------
	 * @access private
     +----------------------------------------------------------
	 * @param string $name 缓存变量名
     +----------------------------------------------------------
	 * @return string
     +----------------------------------------------------------
	 */
	private function filename($name) {
		$name = md5 ( $name );
		if (C ( 'DATA_CACHE_SUBDIR' )) {
			// 使用子目录
			$dir = '';
			for($i = 0; $i < C ( 'DATA_PATH_LEVEL' ); $i ++) {
				$dir .= $name {$i} . '/';
			}
			if (! is_dir ( $this->options ['temp'] . $dir )) {
				mk_dir ( $this->options ['temp'] . $dir );
			}
			$filename = $dir . $this->prefix . $name . '.php';
		} else {
			$filename = $this->prefix . $name . '.php';
		}
		return $this->options ['temp'] . $filename;
	}
	
	/**
     +----------------------------------------------------------
	 * 读取缓存
     +----------------------------------------------------------
	 * @access public
     +----------------------------------------------------------
	 * @param string $name 缓存变量名
     +----------------------------------------------------------
	 * @return mixed
     +----------------------------------------------------------
	 */
	public function get($name) {
		$filename = $this->filename ( $name );
		if (! $this->isConnected () || ! is_file ( $filename )) {
			return false;
		}
		N ( 'cache_read', 1 );
		$content = file_get_contents ( $filename );
		if (false !== $content) {
			$expire = ( int ) substr ( $content, 8, 12 );
			if ($expire != 0 && time () > filemtime ( $filename ) + $expire) {
				//缓存过期删除缓存文件
				unlink ( $filename );
				return false;
			}
			if (C ( 'DATA_CACHE_CHECK' )) { //开启数据校验
				$check = substr ( $content, 20, 32 );
				$content = substr ( $content, 52, - 3 );
				if ($check != md5 ( $content )) { //校验错误
					return false;
				}
			} else {
				$content = substr ( $content, 20, - 3 );
			}
			if (C ( 'DATA_CACHE_COMPRESS' ) && function_exists ( 'gzcompress' )) {
				//启用数据压缩
				$content = gzuncompress ( $content );
			}
			$content = unserialize ( $content );
			return $content;
		} else {
			return false;
		}
	}
	
	/**
     +----------------------------------------------------------
	 * 写入缓存
     +----------------------------------------------------------
	 * @access public
     +----------------------------------------------------------
	 * @param string $name 缓存变量名
	 * @param mixed $value  存储数据
	 * @param int $expire  有效时间 0为永久
     +----------------------------------------------------------
	 * @return boolen
     +----------------------------------------------------------
	 */
	public function set($name, $value, $expire = null) {
		N ( 'cache_write', 1 );
		if (is_null ( $expire )) {
			$expire = $this->options ['expire'];
		}
		$filename = $this->filename ( $name );
		$data = serialize ( $value );
		if (C ( 'DATA_CACHE_COMPRESS' ) && function_exists ( 'gzcompress' )) {
			//数据压缩
			$data = gzcompress ( $data, 3 );
		}
		if (C ( 'DATA_CACHE_CHECK' )) { //开启数据校验
			$check = md5 ( $data );
		} else {
			$check = '';
		}
		$data = "<?php\n//" . sprintf ( '%012d', $expire ) . $check . $data . "\n?>";
		$result = file_put_contents ( $filename, $data );
		if ($result) {
			if ($this->options ['length'] > 0) {
				// 记录缓存队列
				$this->queue ( $name );
			}
			clearstatcache ();
			return true;
		} else {
			return false;
		}
	}
	
	/**
     +----------------------------------------------------------
	 * 删除缓存
     +----------------------------------------------------------
	 * @access public
     +----------------------------------------------------------
	 * @param string $name 缓存变量名
     +----------------------------------------------------------
	 * @return boolen
     +----------------------------------------------------------
	 */
	public function rm($name) {
		return unlink ( $this->filename ( $name ) );
	}
	
	/**
     +----------------------------------------------------------
	 * 清除缓存
     +----------------------------------------------------------
	 * @access public
     +----------------------------------------------------------
	 * @param string $name 缓存变量名
     +----------------------------------------------------------
	 * @return boolen
     +----------------------------------------------------------
	 */
	public function clear() {
		$path = $this->options ['temp'];
		if ($dir = opendir ( $path )) {
			while ( $file = readdir ( $dir ) ) {
				$check = is_dir ( $file );
				if (! $check)
					unlink ( $path . $file );
			}
			closedir ( $dir );
			return true;
		}
	}

}